Full source code website bán hàng thương mại điện tử gần giống shopee
469.106 lượt xem;
1 /*
2 Watermark plugin for jQuery
3 Version: 3.0.4
4 http://jquery-watermark.googlecode.com/
5
6 Copyright (c) 2009-2010 Todd Northrop
7 http://www.speednet.biz/
8
9 January 14, 2010
10
11 Requires: jQuery 1.2.3+
12
13 This program is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 ------------------------------------------------------*/
29
30 (function ($) {
31
32 var
33 // Will speed up references to undefined
34 undefined,
35
36 // String constants for data names
37 dataFlag = "watermark",
38 dataClass = "watermarkClass",
39 dataFocus = "watermarkFocus",
40 dataFormSubmit = "watermarkSubmit",
41 dataMaxLen = "watermarkMaxLength",
42 dataPassword = "watermarkPassword",
43 dataText = "watermarkText",
44
45 // Includes only elements with watermark defined
46 selWatermarkDefined = ":data(" + dataFlag + ")",
47
48 // Includes only elements capable of having watermark
49 selWatermarkAble = ":text,:password,:search,textarea",
50
51 // triggerFns:
52 // Array of function names to look for in the global namespace.
53 // Any such functions found will be hijacked to trigger a call to
54 // hideAll() any time they are called. The default value is the
55 // ASP.NET function that validates the controls on the page
56 // prior to a postback.
57 //
58 // Am I missing other important trigger function(s) to look for?
59 // Please leave me feedback:
60 // http://code.google.com/p/jquery-watermark/issues/list
61 triggerFns = [
62 "Page_ClientValidate"
63 ],
64
65 // Holds a value of true if a watermark was displayed since the last
66 // hideAll() was executed. Avoids repeatedly calling hideAll().
67 pageDirty = false;
68
69 // Extends jQuery with a custom selector - ":data(...)"
70 // :data(<name>) Includes elements that have a specific name defined in the jQuery data collection. (Only the existence of the name is checked; the value is ignored.)
71 // :data(<name>=<value>) Includes elements that have a specific jQuery data name defined, with a specific value associated with it.
72 // :data(<name>!=<value>) Includes elements that have a specific jQuery data name defined, with a value that is not equal to the value specified.
73 // :data(<name>^=<value>) Includes elements that have a specific jQuery data name defined, with a value that starts with the value specified.
74 // :data(<name>$=<value>) Includes elements that have a specific jQuery data name defined, with a value that ends with the value specified.
75 // :data(<name>*=<value>) Includes elements that have a specific jQuery data name defined, with a value that contains the value specified.
76 $.extend($.expr[":"], {
77 "search": function (elem) {
78 return "search" === elem.type;
79 },
80
81 "data": function (element, index, matches, set) {
82 var data, parts = /^((?:[^=!^$*]|[!^$*](?!=))+)(?:([!^$*]?=)(.*))?$/.exec(matches[3]);
83 if (parts) {
84 data = $(element).data(parts[1]);
85
86 if (data !== undefined) {
87
88 if (parts[2]) {
89 data = "" + data;
90
91 switch (parts[2]) {
92 case "=":
93 return (data == parts[3]);
94 case "!=":
95 return (data != parts[3]);
96 case "^=":
97 return (data.slice(0, parts[3].length) == parts[3]);
98 case "$=":
99 return (data.slice(-parts[3].length) == parts[3]);
100 case "*=":
101 return (data.indexOf(parts[3]) !== -1);
102 }
103 }
104
105 return true;
106 }
107 }
108
109 return false;
110 }
111 });
112
113 $.watermark = {
114
115 // Current version number of the plugin
116 version: "3.0.4",
117
118 // Default options used when watermarks are instantiated.
119 // Can be changed to affect the default behavior for all
120 // new or updated watermarks.
121 // BREAKING CHANGE: The $.watermark.className
122 // property that was present prior to version 3.0.2 must
123 // be changed to $.watermark.options.className
124 options: {
125
126 // Default class name for all watermarks
127 className: "watermark",
128
129 // If true, plugin will detect and use native browser support for
130 // watermarks, if available. (e.g., WebKit's placeholder attribute.)
131 useNative: true
132 },
133
134 // Hide one or more watermarks by specifying any selector type
135 // i.e., DOM element, string selector, jQuery matched set, etc.
136 hide: function (selector) {
137 $(selector).filter(selWatermarkDefined).each(
138 function () {
139 $.watermark._hide($(this));
140 }
141 );
142 },
143
144 // Internal use only.
145 _hide: function ($input, focus) {
146
147 if ($input.val() == $input.data(dataText)) {
148 $input.val("");
149
150 // Password type?
151 if ($input.data(dataPassword)) {
152
153 if ($input.attr("type") === "text") {
154 var $pwd = $input.data(dataPassword),
155 $wrap = $input.parent();
156
157 $wrap[0].removeChild($input[0]); // Can't use jQuery methods, because they destroy data
158 $wrap[0].appendChild($pwd[0]);
159 $input = $pwd;
160 }
161 }
162
163 if ($input.data(dataMaxLen)) {
164 $input.attr("maxLength", $input.data(dataMaxLen));
165 $input.removeData(dataMaxLen);
166 }
167
168 if (focus) {
169 $input.attr("autocomplete", "off"); // Avoid NS_ERROR_XPC_JS_THREW_STRING error in Firefox
170 window.setTimeout(
171 function () {
172 $input.select(); // Fix missing cursor in IE
173 }
174 , 0);
175 }
176 }
177
178 $input.removeClass($input.data(dataClass));
179 },
180
181 // Display one or more watermarks by specifying any selector type
182 // i.e., DOM element, string selector, jQuery matched set, etc.
183 // If conditions are not right for displaying a watermark, ensures that watermark is not shown.
184 show: function (selector) {
185 $(selector).filter(selWatermarkDefined).each(
186 function () {
187 $.watermark._show($(this));
188 }
189 );
190 },
191
192 // Internal use only.
193 _show: function ($input) {
194 var val = $input.val(),
195 text = $input.data(dataText),
196 type = $input.attr("type");
197
198 if (((val.length == 0) || (val == text)) && (!$input.data(dataFocus))) {
199 pageDirty = true;
200
201 // Password type?
202 if ($input.data(dataPassword)) {
203
204 if (type === "password") {
205 var $wm = $input.data(dataPassword),
206 $wrap = $input.parent();
207
208 $wrap[0].removeChild($input[0]); // Can't use jQuery methods, because they destroy data
209 $wrap[0].appendChild($wm[0]);
210 $input = $wm;
211 $input.attr("maxLength", text.length);
212 }
213 }
214
215 // Ensure maxLength big enough to hold watermark (input of type="text" or type="search" only)
216 if ((type === "text") || (type === "search")) {
217 var maxLen = $input.attr("maxLength");
218
219 if ((maxLen > 0) && (text.length > maxLen)) {
220 $input.data(dataMaxLen, maxLen);
221 $input.attr("maxLength", text.length);
222 }
223 }
224
225 $input.addClass($input.data(dataClass));
226 $input.val(text);
227 }
228 else {
229 $.watermark._hide($input);
230 }
231 },
232
233 // Hides all watermarks on the current page.
234 hideAll: function () {
235 if (pageDirty) {
236 $.watermark.hide(selWatermarkAble);
237 pageDirty = false;
238 }
239 },
240
241 // Displays all watermarks on the current page.
242 showAll: function () {
243 $.watermark.show(selWatermarkAble);
244 }
245 };
246
247 $.fn.watermark = function (text, options) {
248 /// <summary>
249 /// Set watermark text and class name on all input elements of type="text/password/search" and
250 /// textareas within the matched set. If className is not specified in options, the default is
251 /// "watermark". Within the matched set, only input elements with type="text/password/search"
252 /// and textareas are affected; all other elements are ignored.
253 /// </summary>
254 /// <returns type="jQuery">
255 /// Returns the original jQuery matched set (not just the input and texarea elements).
256 /// </returns>
257 /// <param name="text" type="String">
258 /// Text to display as a watermark when the input or textarea element has an empty value and does not
259 /// have focus. The first time watermark() is called on an element, if this argument is empty (or not
260 /// a String type), then the watermark will have the net effect of only changing the class name when
261 /// the input or textarea element's value is empty and it does not have focus.
262 /// </param>
263 /// <param name="options" type="Object" optional="true">
264 /// Provides the ability to override the default watermark options ($.watermark.options). For backward
265 /// compatibility, if a string value is supplied, it is used as the class name that overrides the class
266 /// name in $.watermark.options.className. Properties include:
267 /// className: When the watermark is visible, the element will be styled using this class name.
268 /// useNative (Boolean or Function): Specifies if native browser support for watermarks will supersede
269 /// plugin functionality. If useNative is a function, the return value from the function will
270 /// determine if native support is used. The function is passed one argument -- a jQuery object
271 /// containing the element being tested as the only element in its matched set -- and the DOM
272 /// element being tested is the object on which the function is invoked (the value of "this").
273 /// </param>
274 /// <remarks>
275 /// The effect of changing the text and class name on an input element is called a watermark because
276 /// typically light gray text is used to provide a hint as to what type of input is required. However,
277 /// the appearance of the watermark can be something completely different: simply change the CSS style
278 /// pertaining to the supplied class name.
279 ///
280 /// The first time watermark() is called on an element, the watermark text and class name are initialized,
281 /// and the focus and blur events are hooked in order to control the display of the watermark. Also, as
282 /// of version 3.0, drag and drop events are hooked to guard against dropped text being appended to the
283 /// watermark. If native watermark support is provided by the browser, it is detected and used, unless
284 /// the useNative option is set to false.
285 ///
286 /// Subsequently, watermark() can be called again on an element in order to change the watermark text
287 /// and/or class name, and it can also be called without any arguments in order to refresh the display.
288 ///
289 /// For example, after changing the value of the input or textarea element programmatically, watermark()
290 /// should be called without any arguments to refresh the display, because the change event is only
291 /// triggered by user actions, not by programmatic changes to an input or textarea element's value.
292 ///
293 /// The one exception to programmatic updates is for password input elements: you are strongly cautioned
294 /// against changing the value of a password input element programmatically (after the page loads).
295 /// The reason is that some fairly hairy code is required behind the scenes to make the watermarks bypass
296 /// IE security and switch back and forth between clear text (for watermarks) and obscured text (for
297 /// passwords). It is *possible* to make programmatic changes, but it must be done in a certain way, and
298 /// overall it is not recommended.
299 /// </remarks>
300
301 var hasText = (typeof(text) === "string"), hasClass;
302
303 if (typeof(options) === "object") {
304 hasClass = (typeof(options.className) === "string");
305 options = $.extend({}, $.watermark.options, options);
306 }
307 else if (typeof(options) === "string") {
308 hasClass = true;
309 options = $.extend({}, $.watermark.options, {className: options});
310 }
311 else {
312 options = $.watermark.options;
313 }
314
315 if (typeof(options.useNative) !== "function") {
316 options.useNative = options.useNative? function () { return true; } : function () { return false; };
317 }
318
319 return this.each(
320 function () {
321 var $input = $(this);
322
323 if (!$input.is(selWatermarkAble)) {
324 return;
325 }
326
327 // Watermark already initialized?
328 if ($input.data(dataFlag)) {
329
330 // If re-defining text or class, first remove existing watermark, then make changes
331 if (hasText || hasClass) {
332 $.watermark._hide($input);
333
334 if (hasText) {
335 $input.data(dataText, text);
336 }
337
338 if (hasClass) {
339 $input.data(dataClass, options.className);
340 }
341 }
342 }
343 else {
344
345 // Detect and use native browser support, if enabled in options
346 if (options.useNative.call(this, $input)) {
347
348 // Placeholder attribute (WebKit)
349 // Big thanks to Opera for the wacky test required
350 if ((("" + $input.css("-webkit-appearance")).replace("undefined", "") !== "") && ($input.attr("tagName") !== "TEXTAREA")) {
351
352 // className is not set because WebKit doesn't appear to have
353 // a separate class name property for placeholders (watermarks).
354 if (hasText) {
355 $input.attr("placeholder", text);
356 }
357
358 // Only set data flag for non-native watermarks (purposely commented-out)
359 // $input.data(dataFlag, 1);
360 return;
361 }
362 }
363
364 $input.data(dataText, hasText? text : "");
365 $input.data(dataClass, options.className);
366 $input.data(dataFlag, 1); // Flag indicates watermark was initialized
367
368 // Special processing for password type
369 if ($input.attr("type") === "password") {
370 var $wrap = $input.wrap("<span>").parent();
371 var $wm = $($wrap.html().replace(/type=["']?password["']?/i, 'type="text"'));
372
373 $wm.data(dataText, $input.data(dataText));
374 $wm.data(dataClass, $input.data(dataClass));
375 $wm.data(dataFlag, 1);
376 $wm.attr("maxLength", text.length);
377
378 $wm.focus(
379 function () {
380 $.watermark._hide($wm, true);
381 }
382 ).bind("dragenter",
383 function () {
384 $.watermark._hide($wm);
385 }
386 ).bind("dragend",
387 function () {
388 window.setTimeout(function () { $wm.blur(); }, 1);
389 }
390 );
391 $input.blur(
392 function () {
393 $.watermark._show($input);
394 }
395 ).bind("dragleave",
396 function () {
397 $.watermark._show($input);
398 }
399 );
400
401 $wm.data(dataPassword, $input);
402 $input.data(dataPassword, $wm);
403 }
404 else {
405
406 $input.focus(
407 function () {
408 $input.data(dataFocus, 1);
409 $.watermark._hide($input, true);
410 }
411 ).blur(
412 function () {
413 $input.data(dataFocus, 0);
414 $.watermark._show($input);
415 }
416 ).bind("dragenter",
417 function () {
418 $.watermark._hide($input);
419 }
420 ).bind("dragleave",
421 function () {
422 $.watermark._show($input);
423 }
424 ).bind("dragend",
425 function () {
426 window.setTimeout(function () { $.watermark._show($input); }, 1);
427 }
428 ).bind("drop",
429 // Firefox makes this lovely function necessary because the dropped text
430 // is merged with the watermark before the drop event is called.
431 function (evt) {
432 var dropText = evt.originalEvent.dataTransfer.getData("Text");
433
434 if ($input.val().replace(dropText, "") === $input.data(dataText)) {
435 $input.val(dropText);
436 }
437
438 $input.focus();
439 }
440 );
441 }
442
443 // In order to reliably clear all watermarks before form submission,
444 // we need to replace the form's submit function with our own
445 // function. Otherwise watermarks won't be cleared when the form
446 // is submitted programmatically.
447 if (this.form) {
448 var form = this.form,
449 $form = $(form);
450
451 if (!$form.data(dataFormSubmit)) {
452 $form.submit($.watermark.hideAll);
453
454 // form.submit exists for all browsers except Google Chrome
455 // (see "else" below for explanation)
456 if (form.submit) {
457 $form.data(dataFormSubmit, form.submit);
458
459 form.submit = (function (f, $f) {
460 return function () {
461 var nativeSubmit = $f.data(dataFormSubmit);
462
463 $.watermark.hideAll();
464
465 if (nativeSubmit.apply) {
466 nativeSubmit.apply(f, Array.prototype.slice.call(arguments));
467 }
468 else {
469 nativeSubmit();
470 }
471 };
472 })(form, $form);
473 }
474 else {
475 $form.data(dataFormSubmit, 1);
476
477 // This strangeness is due to the fact that Google Chrome's
478 // form.submit function is not visible to JavaScript (identifies
479 // as "undefined"). I had to invent a solution here because hours
480 // of Googling (ironically) for an answer did not turn up anything
481 // useful. Within my own form.submit function I delete the form's
482 // submit function, and then call the non-existent function --
483 // which, in the world of Google Chrome, still exists.
484 form.submit = (function (f) {
485 return function () {
486 $.watermark.hideAll();
487 delete f.submit;
488 f.submit();
489 };
490 })(form);
491 }
492 }
493 }
494 }
495
496 $.watermark._show($input);
497 }
498 ).end();
499 };
500
501 // Hijack any functions found in the triggerFns list
502 if (triggerFns.length) {
503
504 // Wait until DOM is ready before searching
505 $(function () {
506 var i, name, fn;
507
508 for (i=triggerFns.length-1; i>=0; i--) {
509 name = triggerFns[i];
510 fn = window[name];
511
512 if (typeof(fn) === "function") {
513 window[name] = (function (origFn) {
514 return function () {
515 $.watermark.hideAll();
516 origFn.apply(null, Array.prototype.slice.call(arguments));
517 };
518 })(fn);
519 }
520 }
521 });
522 }
523
524 })(jQuery);
2 Watermark plugin for jQuery
3 Version: 3.0.4
4 http://jquery-watermark.googlecode.com/
5
6 Copyright (c) 2009-2010 Todd Northrop
7 http://www.speednet.biz/
8
9 January 14, 2010
10
11 Requires: jQuery 1.2.3+
12
13 This program is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 ------------------------------------------------------*/
29
30 (function ($) {
31
32 var
33 // Will speed up references to undefined
34 undefined,
35
36 // String constants for data names
37 dataFlag = "watermark",
38 dataClass = "watermarkClass",
39 dataFocus = "watermarkFocus",
40 dataFormSubmit = "watermarkSubmit",
41 dataMaxLen = "watermarkMaxLength",
42 dataPassword = "watermarkPassword",
43 dataText = "watermarkText",
44
45 // Includes only elements with watermark defined
46 selWatermarkDefined = ":data(" + dataFlag + ")",
47
48 // Includes only elements capable of having watermark
49 selWatermarkAble = ":text,:password,:search,textarea",
50
51 // triggerFns:
52 // Array of function names to look for in the global namespace.
53 // Any such functions found will be hijacked to trigger a call to
54 // hideAll() any time they are called. The default value is the
55 // ASP.NET function that validates the controls on the page
56 // prior to a postback.
57 //
58 // Am I missing other important trigger function(s) to look for?
59 // Please leave me feedback:
60 // http://code.google.com/p/jquery-watermark/issues/list
61 triggerFns = [
62 "Page_ClientValidate"
63 ],
64
65 // Holds a value of true if a watermark was displayed since the last
66 // hideAll() was executed. Avoids repeatedly calling hideAll().
67 pageDirty = false;
68
69 // Extends jQuery with a custom selector - ":data(...)"
70 // :data(<name>) Includes elements that have a specific name defined in the jQuery data collection. (Only the existence of the name is checked; the value is ignored.)
71 // :data(<name>=<value>) Includes elements that have a specific jQuery data name defined, with a specific value associated with it.
72 // :data(<name>!=<value>) Includes elements that have a specific jQuery data name defined, with a value that is not equal to the value specified.
73 // :data(<name>^=<value>) Includes elements that have a specific jQuery data name defined, with a value that starts with the value specified.
74 // :data(<name>$=<value>) Includes elements that have a specific jQuery data name defined, with a value that ends with the value specified.
75 // :data(<name>*=<value>) Includes elements that have a specific jQuery data name defined, with a value that contains the value specified.
76 $.extend($.expr[":"], {
77 "search": function (elem) {
78 return "search" === elem.type;
79 },
80
81 "data": function (element, index, matches, set) {
82 var data, parts = /^((?:[^=!^$*]|[!^$*](?!=))+)(?:([!^$*]?=)(.*))?$/.exec(matches[3]);
83 if (parts) {
84 data = $(element).data(parts[1]);
85
86 if (data !== undefined) {
87
88 if (parts[2]) {
89 data = "" + data;
90
91 switch (parts[2]) {
92 case "=":
93 return (data == parts[3]);
94 case "!=":
95 return (data != parts[3]);
96 case "^=":
97 return (data.slice(0, parts[3].length) == parts[3]);
98 case "$=":
99 return (data.slice(-parts[3].length) == parts[3]);
100 case "*=":
101 return (data.indexOf(parts[3]) !== -1);
102 }
103 }
104
105 return true;
106 }
107 }
108
109 return false;
110 }
111 });
112
113 $.watermark = {
114
115 // Current version number of the plugin
116 version: "3.0.4",
117
118 // Default options used when watermarks are instantiated.
119 // Can be changed to affect the default behavior for all
120 // new or updated watermarks.
121 // BREAKING CHANGE: The $.watermark.className
122 // property that was present prior to version 3.0.2 must
123 // be changed to $.watermark.options.className
124 options: {
125
126 // Default class name for all watermarks
127 className: "watermark",
128
129 // If true, plugin will detect and use native browser support for
130 // watermarks, if available. (e.g., WebKit's placeholder attribute.)
131 useNative: true
132 },
133
134 // Hide one or more watermarks by specifying any selector type
135 // i.e., DOM element, string selector, jQuery matched set, etc.
136 hide: function (selector) {
137 $(selector).filter(selWatermarkDefined).each(
138 function () {
139 $.watermark._hide($(this));
140 }
141 );
142 },
143
144 // Internal use only.
145 _hide: function ($input, focus) {
146
147 if ($input.val() == $input.data(dataText)) {
148 $input.val("");
149
150 // Password type?
151 if ($input.data(dataPassword)) {
152
153 if ($input.attr("type") === "text") {
154 var $pwd = $input.data(dataPassword),
155 $wrap = $input.parent();
156
157 $wrap[0].removeChild($input[0]); // Can't use jQuery methods, because they destroy data
158 $wrap[0].appendChild($pwd[0]);
159 $input = $pwd;
160 }
161 }
162
163 if ($input.data(dataMaxLen)) {
164 $input.attr("maxLength", $input.data(dataMaxLen));
165 $input.removeData(dataMaxLen);
166 }
167
168 if (focus) {
169 $input.attr("autocomplete", "off"); // Avoid NS_ERROR_XPC_JS_THREW_STRING error in Firefox
170 window.setTimeout(
171 function () {
172 $input.select(); // Fix missing cursor in IE
173 }
174 , 0);
175 }
176 }
177
178 $input.removeClass($input.data(dataClass));
179 },
180
181 // Display one or more watermarks by specifying any selector type
182 // i.e., DOM element, string selector, jQuery matched set, etc.
183 // If conditions are not right for displaying a watermark, ensures that watermark is not shown.
184 show: function (selector) {
185 $(selector).filter(selWatermarkDefined).each(
186 function () {
187 $.watermark._show($(this));
188 }
189 );
190 },
191
192 // Internal use only.
193 _show: function ($input) {
194 var val = $input.val(),
195 text = $input.data(dataText),
196 type = $input.attr("type");
197
198 if (((val.length == 0) || (val == text)) && (!$input.data(dataFocus))) {
199 pageDirty = true;
200
201 // Password type?
202 if ($input.data(dataPassword)) {
203
204 if (type === "password") {
205 var $wm = $input.data(dataPassword),
206 $wrap = $input.parent();
207
208 $wrap[0].removeChild($input[0]); // Can't use jQuery methods, because they destroy data
209 $wrap[0].appendChild($wm[0]);
210 $input = $wm;
211 $input.attr("maxLength", text.length);
212 }
213 }
214
215 // Ensure maxLength big enough to hold watermark (input of type="text" or type="search" only)
216 if ((type === "text") || (type === "search")) {
217 var maxLen = $input.attr("maxLength");
218
219 if ((maxLen > 0) && (text.length > maxLen)) {
220 $input.data(dataMaxLen, maxLen);
221 $input.attr("maxLength", text.length);
222 }
223 }
224
225 $input.addClass($input.data(dataClass));
226 $input.val(text);
227 }
228 else {
229 $.watermark._hide($input);
230 }
231 },
232
233 // Hides all watermarks on the current page.
234 hideAll: function () {
235 if (pageDirty) {
236 $.watermark.hide(selWatermarkAble);
237 pageDirty = false;
238 }
239 },
240
241 // Displays all watermarks on the current page.
242 showAll: function () {
243 $.watermark.show(selWatermarkAble);
244 }
245 };
246
247 $.fn.watermark = function (text, options) {
248 /// <summary>
249 /// Set watermark text and class name on all input elements of type="text/password/search" and
250 /// textareas within the matched set. If className is not specified in options, the default is
251 /// "watermark". Within the matched set, only input elements with type="text/password/search"
252 /// and textareas are affected; all other elements are ignored.
253 /// </summary>
254 /// <returns type="jQuery">
255 /// Returns the original jQuery matched set (not just the input and texarea elements).
256 /// </returns>
257 /// <param name="text" type="String">
258 /// Text to display as a watermark when the input or textarea element has an empty value and does not
259 /// have focus. The first time watermark() is called on an element, if this argument is empty (or not
260 /// a String type), then the watermark will have the net effect of only changing the class name when
261 /// the input or textarea element's value is empty and it does not have focus.
262 /// </param>
263 /// <param name="options" type="Object" optional="true">
264 /// Provides the ability to override the default watermark options ($.watermark.options). For backward
265 /// compatibility, if a string value is supplied, it is used as the class name that overrides the class
266 /// name in $.watermark.options.className. Properties include:
267 /// className: When the watermark is visible, the element will be styled using this class name.
268 /// useNative (Boolean or Function): Specifies if native browser support for watermarks will supersede
269 /// plugin functionality. If useNative is a function, the return value from the function will
270 /// determine if native support is used. The function is passed one argument -- a jQuery object
271 /// containing the element being tested as the only element in its matched set -- and the DOM
272 /// element being tested is the object on which the function is invoked (the value of "this").
273 /// </param>
274 /// <remarks>
275 /// The effect of changing the text and class name on an input element is called a watermark because
276 /// typically light gray text is used to provide a hint as to what type of input is required. However,
277 /// the appearance of the watermark can be something completely different: simply change the CSS style
278 /// pertaining to the supplied class name.
279 ///
280 /// The first time watermark() is called on an element, the watermark text and class name are initialized,
281 /// and the focus and blur events are hooked in order to control the display of the watermark. Also, as
282 /// of version 3.0, drag and drop events are hooked to guard against dropped text being appended to the
283 /// watermark. If native watermark support is provided by the browser, it is detected and used, unless
284 /// the useNative option is set to false.
285 ///
286 /// Subsequently, watermark() can be called again on an element in order to change the watermark text
287 /// and/or class name, and it can also be called without any arguments in order to refresh the display.
288 ///
289 /// For example, after changing the value of the input or textarea element programmatically, watermark()
290 /// should be called without any arguments to refresh the display, because the change event is only
291 /// triggered by user actions, not by programmatic changes to an input or textarea element's value.
292 ///
293 /// The one exception to programmatic updates is for password input elements: you are strongly cautioned
294 /// against changing the value of a password input element programmatically (after the page loads).
295 /// The reason is that some fairly hairy code is required behind the scenes to make the watermarks bypass
296 /// IE security and switch back and forth between clear text (for watermarks) and obscured text (for
297 /// passwords). It is *possible* to make programmatic changes, but it must be done in a certain way, and
298 /// overall it is not recommended.
299 /// </remarks>
300
301 var hasText = (typeof(text) === "string"), hasClass;
302
303 if (typeof(options) === "object") {
304 hasClass = (typeof(options.className) === "string");
305 options = $.extend({}, $.watermark.options, options);
306 }
307 else if (typeof(options) === "string") {
308 hasClass = true;
309 options = $.extend({}, $.watermark.options, {className: options});
310 }
311 else {
312 options = $.watermark.options;
313 }
314
315 if (typeof(options.useNative) !== "function") {
316 options.useNative = options.useNative? function () { return true; } : function () { return false; };
317 }
318
319 return this.each(
320 function () {
321 var $input = $(this);
322
323 if (!$input.is(selWatermarkAble)) {
324 return;
325 }
326
327 // Watermark already initialized?
328 if ($input.data(dataFlag)) {
329
330 // If re-defining text or class, first remove existing watermark, then make changes
331 if (hasText || hasClass) {
332 $.watermark._hide($input);
333
334 if (hasText) {
335 $input.data(dataText, text);
336 }
337
338 if (hasClass) {
339 $input.data(dataClass, options.className);
340 }
341 }
342 }
343 else {
344
345 // Detect and use native browser support, if enabled in options
346 if (options.useNative.call(this, $input)) {
347
348 // Placeholder attribute (WebKit)
349 // Big thanks to Opera for the wacky test required
350 if ((("" + $input.css("-webkit-appearance")).replace("undefined", "") !== "") && ($input.attr("tagName") !== "TEXTAREA")) {
351
352 // className is not set because WebKit doesn't appear to have
353 // a separate class name property for placeholders (watermarks).
354 if (hasText) {
355 $input.attr("placeholder", text);
356 }
357
358 // Only set data flag for non-native watermarks (purposely commented-out)
359 // $input.data(dataFlag, 1);
360 return;
361 }
362 }
363
364 $input.data(dataText, hasText? text : "");
365 $input.data(dataClass, options.className);
366 $input.data(dataFlag, 1); // Flag indicates watermark was initialized
367
368 // Special processing for password type
369 if ($input.attr("type") === "password") {
370 var $wrap = $input.wrap("<span>").parent();
371 var $wm = $($wrap.html().replace(/type=["']?password["']?/i, 'type="text"'));
372
373 $wm.data(dataText, $input.data(dataText));
374 $wm.data(dataClass, $input.data(dataClass));
375 $wm.data(dataFlag, 1);
376 $wm.attr("maxLength", text.length);
377
378 $wm.focus(
379 function () {
380 $.watermark._hide($wm, true);
381 }
382 ).bind("dragenter",
383 function () {
384 $.watermark._hide($wm);
385 }
386 ).bind("dragend",
387 function () {
388 window.setTimeout(function () { $wm.blur(); }, 1);
389 }
390 );
391 $input.blur(
392 function () {
393 $.watermark._show($input);
394 }
395 ).bind("dragleave",
396 function () {
397 $.watermark._show($input);
398 }
399 );
400
401 $wm.data(dataPassword, $input);
402 $input.data(dataPassword, $wm);
403 }
404 else {
405
406 $input.focus(
407 function () {
408 $input.data(dataFocus, 1);
409 $.watermark._hide($input, true);
410 }
411 ).blur(
412 function () {
413 $input.data(dataFocus, 0);
414 $.watermark._show($input);
415 }
416 ).bind("dragenter",
417 function () {
418 $.watermark._hide($input);
419 }
420 ).bind("dragleave",
421 function () {
422 $.watermark._show($input);
423 }
424 ).bind("dragend",
425 function () {
426 window.setTimeout(function () { $.watermark._show($input); }, 1);
427 }
428 ).bind("drop",
429 // Firefox makes this lovely function necessary because the dropped text
430 // is merged with the watermark before the drop event is called.
431 function (evt) {
432 var dropText = evt.originalEvent.dataTransfer.getData("Text");
433
434 if ($input.val().replace(dropText, "") === $input.data(dataText)) {
435 $input.val(dropText);
436 }
437
438 $input.focus();
439 }
440 );
441 }
442
443 // In order to reliably clear all watermarks before form submission,
444 // we need to replace the form's submit function with our own
445 // function. Otherwise watermarks won't be cleared when the form
446 // is submitted programmatically.
447 if (this.form) {
448 var form = this.form,
449 $form = $(form);
450
451 if (!$form.data(dataFormSubmit)) {
452 $form.submit($.watermark.hideAll);
453
454 // form.submit exists for all browsers except Google Chrome
455 // (see "else" below for explanation)
456 if (form.submit) {
457 $form.data(dataFormSubmit, form.submit);
458
459 form.submit = (function (f, $f) {
460 return function () {
461 var nativeSubmit = $f.data(dataFormSubmit);
462
463 $.watermark.hideAll();
464
465 if (nativeSubmit.apply) {
466 nativeSubmit.apply(f, Array.prototype.slice.call(arguments));
467 }
468 else {
469 nativeSubmit();
470 }
471 };
472 })(form, $form);
473 }
474 else {
475 $form.data(dataFormSubmit, 1);
476
477 // This strangeness is due to the fact that Google Chrome's
478 // form.submit function is not visible to JavaScript (identifies
479 // as "undefined"). I had to invent a solution here because hours
480 // of Googling (ironically) for an answer did not turn up anything
481 // useful. Within my own form.submit function I delete the form's
482 // submit function, and then call the non-existent function --
483 // which, in the world of Google Chrome, still exists.
484 form.submit = (function (f) {
485 return function () {
486 $.watermark.hideAll();
487 delete f.submit;
488 f.submit();
489 };
490 })(form);
491 }
492 }
493 }
494 }
495
496 $.watermark._show($input);
497 }
498 ).end();
499 };
500
501 // Hijack any functions found in the triggerFns list
502 if (triggerFns.length) {
503
504 // Wait until DOM is ready before searching
505 $(function () {
506 var i, name, fn;
507
508 for (i=triggerFns.length-1; i>=0; i--) {
509 name = triggerFns[i];
510 fn = window[name];
511
512 if (typeof(fn) === "function") {
513 window[name] = (function (origFn) {
514 return function () {
515 $.watermark.hideAll();
516 origFn.apply(null, Array.prototype.slice.call(arguments));
517 };
518 })(fn);
519 }
520 }
521 });
522 }
523
524 })(jQuery);